import { Inject, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import * as ccxt from 'ccxt';
import * as cryptojs from 'crypto-js';
import * as TelegramBot from 'node-telegram-bot-api';
import { User } from 'repos-model';
import { Repository } from 'typeorm';
import { config } from '../../config';
import { ETransactionType, Subscribe, Transaction } from '../../model';
import { usr } from './dto/auth.dto';
import { keys } from './dto/keys.dto';
import { refill } from './dto/refill.dto';
import { notif } from './dto/updateNotif.dto';

@Injectable()
export class UserService {
    constructor(
        @InjectRepository(User)
        private userRepository: Repository<User>,
        @InjectRepository(Subscribe)
        private subscribeRepository: Repository<Subscribe>,
        @InjectRepository(Transaction)
        private transactionRepository: Repository<Transaction>,
        @Inject('TelegramBot')
        private bot: TelegramBot
    ) {}

    /**
     * Шифрование данных
     * @param text
     * @private
     */

    private encrypt(text: string) {
        try {
            const encrypted = cryptojs.AES.encrypt(text, config.secure.secretKey);
            return encrypted.toString();
        } catch (error) {
            console.log('Ошибка шифрования');
        }
    }

    /**
     * Расшифрование зашифрованных данных
     * @param text
     * @private
     */
    private decrypt(text: string) {
        try {
            const decrypted = cryptojs.AES.decrypt(text, config.secure.secretKey);
            return decrypted.toString();
        } catch (error) {
            console.log('Ошибка шифрования');
        }
    }

    /**
     * Проверка Apikey & secretKey на binance
     * Если ключи не верны, то await binance.fetchBalance выдаст ошибку, иначе пройдет все гладко
     * @param keys
     * @private
     */
    private async checkApiKeys(keys: keys) {
        try {
            const binance = new ccxt.binance({
                apiKey: keys.apiKey,
                secret: keys.secretKey,
                options: {
                    defaultType: 'future',
                    adjustForTimeDifference: true,
                    createMarketBuyOrderRequiresPrice: true,
                },
            });

            binance.setSandboxMode(true);

            const balance = await binance.fetchBalance();
            return true;
        } catch (error) {
            console.log('Ключи невалидны');
            return false;
        }
    }

    /**
     * Авторизация пользователя
     * Проверка ключей и создание записи в базе данных
     * @param keys telegramID, apiKey, secretKey
     */
    async loginUser(keys: keys) {
        try {
            // const isValid = await this.checkApiKeys(keys);

            const isValid = true;
            if (isValid) {
                await this.userRepository.update(
                    { telegramId: keys.telegramId },
                    {
                        apiKey: this.encrypt(keys.apiKey),
                        secretKey: this.encrypt(keys.secretKey),
                        validKey: true,
                        dateAddKey: new Date(),
                    }
                );
                return true;
            }
            // if (isValid) {
            //     await this.userRepository.update(
            //         { telegramId: keys.telegramId },
            //         {
            //             apiKey: keys.apiKey,
            //             secretKey: keys.secretKey,
            //             validKey: true,
            //             dateAddKey: new Date(),
            //         }
            //     );
            //     console.log(keys);
            //     return true;
            // }
            return false;
        } catch (error) {
            console.log('Ошибка авторизации');
            return false;
        }
    }

    /**
     * Проверка наличия ApiKey при загрузке сайта
     * @param id
     */
    async authCheck(id: usr) {
        try {
            const user = await this.userRepository.findOneBy({
                telegramId: id.id,
            });

            if (user?.apiKey) {
                if (user.role === 'User') {
                    return 'user';
                } else {
                    return 'trader';
                }
            }
            return false;
        } catch (error) {
            console.log(error);
            return false;
        }
    }

    /**
     * Запрос на получение текущего баланса пользователя
     * @param usr
     */
    async checkBalance(usr: usr) {
        try {
            const user = await this.userRepository.findOneByOrFail({
                telegramId: usr.id,
            });

            return user.balance;
        } catch (error) {
            console.log(error);
            return false;
        }
    }

    async checkTransactionList(usr: usr) {
        try {
            const transactionList = await this.transactionRepository
                .createQueryBuilder('transaction')
                .select([
                    'transaction.typeTransaction as type',
                    'transaction.amount as sum',
                    'transaction.created_at as date',
                ])
                .where('transaction.userTelegramId = :id AND transaction.result = true', { id: usr.id })
                .getRawMany();

            return transactionList;
        } catch (error) {
            console.log(error);
            return false;
        }
    }

    /**
     * Пополенение баланса
     * Автоматом изменение баланса в отношении User и создание операции в Transaction + итог операции сообщается в чате пользователя
     * @param transaction
     */
    async refill(transaction: refill) {
        try {
            // Получение стоимости подписки за день и формирование цены от дней подписки * стоимость за 1 день
            // const amount = await this.subscribeRepository
            // 	.createQueryBuilder('subscribe')
            // 	.select(['subscribe.sum'])
            // 	.where('subscribe.userTelegramId = :id', {
            // 		id: transaction.telegramId,
            // 	})
            // 	.getOne();
            //
            // const trans = new Transaction({
            // 	userTelegramId: transaction.telegramId,
            // 	typeTransaction: ETransactionType.Refill,
            // 	amount: +transaction.amount * amount.sum,
            // 	result: false,
            // });
            const trans = new Transaction({
                userTelegramId: transaction.telegramId,
                typeTransaction: ETransactionType.Refill,
                amount: +transaction.amount,
                result: false,
            });
            await this.transactionRepository.save(trans);
            const result = true; // Вместо нее будет ответ от микросервеси, норм операция прошла или нет

            if (result) {
                await this.transactionRepository.update(
                    {
                        id: trans.id,
                    },
                    { result: true }
                );
                // Для формирования суммы от стоимости подписки
                // await this.userRepository.increment(
                // 	{ telegramId: transaction.telegramId },
                // 	'balance',
                // 	+transaction.amount * amount.sum,
                // );
                await this.userRepository.increment(
                    { telegramId: transaction.telegramId },
                    'balance',
                    +transaction.amount
                );
                // await this.bot.sendMessage(transaction.telegramId, 'Payment was successful');
                return true;
            } else {
                // await this.bot.sendMessage(transaction.telegramId, 'Payment canceled');
                return false;
            }
        } catch (error) {
            // await this.bot.sendMessage(transaction.telegramId, 'Payment canceled');
            console.log(error);
            return false;
        }
    }

    async updateNotification() {
        try {
            const expiredDate = new Date();
            expiredDate.setDate(expiredDate.getDate() + 7);

            const query = await this.userRepository
                .createQueryBuilder('user')
                .select(['user.telegramId as id', 'user.validKey as validKey', 'user.dateAddKey as date'])
                .where(
                    "user.validKey = :validKey OR user.dateAddKey + INTERVAL '3 month' BETWEEN :currentDate AND :expiredDate",
                    {
                        validKey: false,
                        currentDate: new Date(),
                        expiredDate: expiredDate,
                    }
                )
                .getRawMany();

            query.map((item: notif) => {
                if (!item.validkey) {
                    this.bot.sendMessage(item.id, 'У вас истек срок годности Api ключа');
                } else {
                    this.bot.sendMessage(
                        item.id,
                        `Ваш ключ истечет через ${Math.floor(
                            Math.abs(
                                new Date().setDate(new Date().getDate() + 7) -
                                    new Date(item.date).setMonth(new Date(item.date).getMonth() + 3)
                            ) / 86400000
                        )} дней`
                    );
                }
            });

            return true;
        } catch (error) {
            console.log(error);
            return false;
        }
    }
}
